#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <assert.h>
#include <stdbool.h>

#include "menu.h"
#include "event.h"
#include "key.h"
#include "v4l2overlay.h"
#include "ICM20948.h"

#include "log2file.h"

icon_normal_t normal;

static void update_gui_normal(UICtx_t *pobj)
{
    update_icon_normal(&normal, pobj);
}

static void update_gui_mainmenu1(UICtx_t *pobj)
{
    update_icon_mainmenu1(&normal, pobj);
}

static void update_gui_image(UICtx_t *pobj)
{
    update_icon_image(&normal, pobj);
}

static void update_gui_image_adjust(UICtx_t *pobj)
{
    update_icon_image_adjust(&normal, pobj);
}

static void update_gui_image_setting(UICtx_t *pobj)
{
    update_icon_image_setting(&normal, pobj);
}

static void update_gui_camera_setting(UICtx_t *pobj)
{
    update_icon_camera_setting(&normal, pobj);
}

static void update_gui_WB_setting(UICtx_t *pobj)
{
    update_icon_WB_setting(&normal, pobj);
}

static void update_gui_reticle(UICtx_t *pobj)
{
    update_icon_reticle(&normal, pobj);
}

static void update_gui_cross_color_setting(UICtx_t *pobj)
{
    update_icon_cross_color_setting(&normal, pobj);
}

static void update_gui_gun_cal(UICtx_t *pobj)
{
    update_icon_gun_cal(&normal, pobj);
}

static void update_gui_nine_axis_setting(UICtx_t *pobj)
{
    update_icon_nine_axis_setting(&normal, pobj);
}

static void update_gui_system(UICtx_t *pobj)
{
    update_icon_system(&normal, pobj);
}

static void update_gui_language(UICtx_t *pobj)
{
    update_icon_language(&normal, pobj);
}

static void update_gui_compass_cal(UICtx_t *pobj)
{
    update_icon_compass_cal(&normal, pobj);
}

static void update_gui_factory_reset(UICtx_t *pobj)
{
    update_icon_factory_reset(&normal, pobj);
}

static void update_gui_ver_info(UICtx_t *pobj)
{
    update_icon_ver_info(&normal, pobj);
}

static void update_gui_engineering_update(UICtx_t *pobj)
{
    update_icon_engineering_update(&normal, pobj);
}

void handle_gui(UICtx_t * pobj, int actions)
{	
    SDL_Renderer *renderer = (SDL_Renderer *)pobj->pgui;

    if (EGUI_INIT == actions) {
        //初始化屏幕
        normal.renderer = renderer;
    } else if (EGUI_UPDATE == actions) {
        switch(pobj->curid)
        {
        case id_normal:
            update_gui_normal(pobj);
            break;
        case id_mainmenu1:
            update_gui_mainmenu1(pobj);
            break;
        case id_image:
            update_gui_image(pobj);
            break;
        case id_image_adjust:
            update_gui_image_adjust(pobj);
            break;
        case id_image_setting:
            update_gui_image_setting(pobj);
            break;
        case id_camera_setting:
            update_gui_camera_setting(pobj);
            break;
        case id_WB_setting:
            update_gui_WB_setting(pobj);
            break;
        case id_reticle:
            update_gui_reticle(pobj);
            break;
        case id_cross_color_setting:
            update_gui_cross_color_setting(pobj);
            break;
        case id_gun_cal:
            update_gui_gun_cal(pobj);
            break;
        case id_nine_axis_setting:
            update_gui_nine_axis_setting(pobj);
            break;
        case id_system:
            update_gui_system(pobj);
            break;
        case id_language:
            update_gui_language(pobj);
            break;
        case id_compass_cal:
            update_gui_compass_cal(pobj);
            break;
        case id_factory_reset:
            update_gui_factory_reset(pobj);
            break;
        case id_ver_info:
            update_gui_ver_info(pobj);
            break;
        case id_engineering:
            update_gui_engineering_update(pobj);
            break;
        }
        
        // flip the backbuffer
        // this means that everything that we prepared behind the screens is actually shown
        //SDL_RenderPresent(renderer);
    }
    return;
}

static unsigned int bExit = 0, bIsDaemon = 0;
static void onStop(int sig)
{
    printf("exit!!!\n");
    bExit = 1;
    sleep(1);
    exit(0);
}

unsigned int onExit()
{
    return (!bExit);
}

static void print_usage(void)
{
    fprintf(stderr,	"Usage:\n"
                "    sdl [-D] \n"
                "Options:\n"
                "    -D                 Run as Daemon\n"
                "    -h                 This help\n");
}

int main(int argc, char *argv[])
{
    int i;
    while ((i=getopt(argc, argv, "Dh")) != -1)
    {
        switch(i)
        {
        case 'D':
            bIsDaemon = 1;
            break;
        case 'h':
        default:
            print_usage();
            exit(0);
        }
    }
    
    /* run as Daemon*/
    if (bIsDaemon) {
        daemon(1, 1);	// 主要用于希望脱离控制台，以守护进程形式在后台运行的程序。
    }
    
    // variable declarations
    SDL_Window *win = NULL;
    SDL_Renderer *renderer = NULL;

    // !register signal
    signal(SIGTERM, onStop);
    signal(SIGINT, onStop);

    // 设置SDL的环境变量
    // https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlenvvars.html
    setenv("SDL_VIDEODRIVER","dummy",0);
    setenv("SDL_FBACCEL","0",0);
    setenv("SDL_FBDEV","/dev/fb2",0);
    setenv("SDL_VIDEO_YUV_DIRECT","1",0);
    // setenv("SDL_VIDEO_DUMMY_SAVE_FRAMES","1",0);

    // Initialize SDL.
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("SDL_Init failed: %s\n", SDL_GetError());
        return -1;
    }

    if(TTF_Init() < 0) {
        printf("TTF_Init failed: %s\n", TTF_GetError());
        return -1;
    }
    
    UICtx_t *pdev = getUICtx();
    Init_UICtx(pdev);

    // create the window and renderer
    // note that the renderer is accelerated
    win = SDL_CreateWindow("Image Loading", 0, 0, pdev->res_info.osd_width, pdev->res_info.osd_height, 0);
    renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE);
    if(NULL == renderer) {
        printf("SDL_CreateRenderer: %s\n", SDL_GetError());
        return -1;
    }

    // SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
    // SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
    // UICtx_t *pdev = getUICtx();
    // Init_UICtx(pdev);
    pdev->pgui = renderer;

    // 加载资源，比较耗时间
    // 避免运行过程闪屏
    handle_gui(pdev, EGUI_INIT);
    handle_gui(pdev, EGUI_UPDATE);

    SDL_v4l2_driver_init(win);
    SDL_v4l2_RenderMemory(win, 0);	// 避免出现花屏
    SDL_v4l2_RenderMemory(win, 1);	// 避免出现花屏
    SDL_v4l2_RenderMemory(win, 2);	// 避免出现花屏
    SDL_v4l2_start();

    ICM_20948_Init();
    create_keys_thread();
    create_200ms_thread(pdev);

    // main loop
    while (!bExit) 
    {	
        // event handling
        SDL_Event e;
        if (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                break;
            } else if (e.type == SDL_KEYUP) {
                eKeyVal key = e.key.keysym.sym;
                if(handle_event(pdev, key) > 0) {
                    if (0 == SDL_v4l2_RenderMem_Pull(win)) {
                        handle_gui(pdev, 1);
                        SDL_v4l2_RenderMem_Push(win);
                    }
                }
            }
        } else {
            usleep(100 * 1000);
            if (0 == SDL_v4l2_RenderMem_Pull(win)) {
                handle_gui(pdev, 1);
                SDL_v4l2_RenderMem_Push(win);
            }
        }
    }

    SDL_v4l2_driver_deinit();
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(win);
    return 0;
}